package com.cloud.hpj;

import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cloud.model.HpjPayResponse;
import com.cloud.model.HpjQueryPayStatusResponse;
import com.cloud.model.PayRequest;
import org.springframework.stereotype.Service;

@Service
public class PayUtils {

    /**
     * @return
     */
    public HpjPayResponse createPay(PayRequest payRequest) {
        try {
            Map<String, Object> sortParams = new HashMap<>();
            sortParams.put("version", "1.1");
//			sortParams.put("redirect", "Y");
            sortParams.put("appid", payRequest.getAppid());
            sortParams.put("trade_order_id", payRequest.getTradeOrderId());
//			sortParams.put("payment", "wechat");
            //支付金额，单位（元）
            sortParams.put("total_fee", payRequest.getPayAmount());
            sortParams.put("title", payRequest.getGoodsName());
            sortParams.put("time", getSecondTimestamp(new Date()));
//            可选。用户取消支付后，我们可能引导用户跳转到这个网址上重新进行支付
            sortParams.put("callback_url", payRequest.getCallbackUrl());

            //必填。用户支付成功后，我们服务器会主动发送一个post消息到这个网址(注意：当前接口内，SESSION内容无效)
            sortParams.put("notify_url", payRequest.getNotifyUrl());

            //可选。用户支付成功后，我们会让用户浏览器自动跳转到这个网址
            sortParams.put("return_url", payRequest.getReturnUrl());
            sortParams.put("plugins", payRequest.getMemo());
//            固定值"WAP"，H5支付通道请求必填。
//            sortParams.put("type","WAP");
            sortParams.put("nonce_str", getRandomNumber(9));
            sortParams.put("hash", createSign(sortParams, payRequest.getAppsecret()));
            String response = HttpUtil.post("https://api.xunhupay.com/payment/do.html", JSONUtil.toJsonStr(sortParams));
            HpjPayResponse hpjPayResponse = JSONUtil.toBean(response, HpjPayResponse.class);
            return hpjPayResponse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //判断是否支付成功
    public String notify(HpjSuccessResponse response, PayRequest payRequestData) {
        //验证hash一至性
        String hash = response.getHash();
        Map<String, Object> hashSortParams = BeanUtil.beanToMap(response);
        hashSortParams.remove("hash");
        String newHash = createSign(hashSortParams, payRequestData.getAppsecret());
        if (!hash.equals(newHash)) {
            //如果两个hash不一至
            return "fail";
        }
        //验证hash一至性 结束
        HpjQueryPayStatusResponse hpjQueryPayStatusResponse = queryPayStatus(response.getTrade_order_id(), payRequestData);
        return hpjQueryPayStatusResponse.getStatus();
    }

    public HpjQueryPayStatusResponse queryPayStatus(String trade_order_id, PayRequest payRequestData) {
        Map<String, Object> sortParams = new HashMap<>();
        sortParams.put("appid", payRequestData.getAppid());
        sortParams.put("out_trade_order", trade_order_id);
        sortParams.put("time", getSecondTimestamp(new Date()));
        sortParams.put("nonce_str", getRandomNumber(9));
        sortParams.put("hash", createSign(sortParams, payRequestData.getAppsecret()));
        String resp = HttpUtil.post("https://api.xunhupay.com/payment/query.html", sortParams);
        JSONObject jsonObject = JSONUtil.parseObj(resp);
        HpjQueryPayStatusResponse hpjQueryPayStatusResponse = new HpjQueryPayStatusResponse();
        hpjQueryPayStatusResponse.setStatus("fail");
        if (jsonObject != null) {
            Integer errorcode = Convert.toInt(jsonObject.get("errcode"), 500);
            if (errorcode == 0) {
                JSONObject jsonObjectData = JSONUtil.parseObj(jsonObject.get("data"));
                String status = Convert.toStr(jsonObjectData.get("status"), "");
                String open_order_id = Convert.toStr(jsonObjectData.get("open_order_id"), "");
                if (status.equals("OD")) {
                    //                    data.status ：OD(支付成功)，WP(待支付),CD(已取消)
                    hpjQueryPayStatusResponse.setStatus("success");
                    hpjQueryPayStatusResponse.setOpen_order_id(open_order_id);

                }
            }
        }
        return hpjQueryPayStatusResponse;
    }

    /**
     * 生成密钥
     *
     * @param params
     * @param privateKey
     * @return
     */
    public static String createSign(Map<String, Object> params, String privateKey) {

        // 使用HashMap，并使用Arrays.sort排序
        String[] sortedKeys = params.keySet().toArray(new String[]{});
        Arrays.sort(sortedKeys);// 排序请求参数
        StringBuilder builder = new StringBuilder();
        for (String key : sortedKeys) {
            if (key.equals("hash") || StrUtil.isEmpty(Convert.toStr(params.get(key)))) {
                continue;
            }
            builder.append(key).append("=").append(params.get(key)).append("&");
        }
        String result = builder.deleteCharAt(builder.length() - 1).toString();

        /**
         * 拼接上appsecret
         */
        String stringSignTemp = result + privateKey;

        String signValue = SecureUtil.md5(stringSignTemp);
        return signValue;
    }

    /**
     * 获取精确到秒的时间戳   原理 获取毫秒时间戳，因为 1秒 = 100毫秒 去除后三位 就是秒的时间戳
     *
     * @return
     */
    public static int getSecondTimestamp(Date date) {
        if (null == date) {
            return 0;
        }
        String timestamp = String.valueOf(date.getTime());
        int length = timestamp.length();
        if (length > 3) {
            return Integer.valueOf(timestamp.substring(0, length - 3));
        } else {
            return 0;
        }
    }

    /**
     * 生成一个随机数字
     *
     * @param length 长度自定义
     * @return
     */
    public static String getRandomNumber(int length) {
        String str = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < length; ++i) {
            int number = random.nextInt(str.length());
            sb.append(str.charAt(number));
        }

        return sb.toString();
    }
}
